#pragma once

#include <linux/printk.h>
#include <linux/stddef.h>
#include <linux/gfp_types.h>
#include <linux/align.h>

#ifdef CONFIG_MMU
#include <linux/pgtable.h>
#include <linux/mm_types.h>
#endif

void mm_core_init(void);

void *page_address(const struct page *page);

#ifdef CONFIG_MMU

#define VM_MIXEDMAP 0x10000000   /* Can contain "struct page" and pure PFN pages */
#define VM_HUGEPAGE 0x20000000   /* MADV_HUGEPAGE marked this vma */
#define VM_NOHUGEPAGE 0x40000000 /* MADV_NOHUGEPAGE marked this vma */
#define VM_MERGEABLE 0x80000000  /* KSM may merge identical pages */

#define VM_PFNMAP 0x00000400  /* Page-ranges managed without "struct page", just pure PFN */
#define VM_UFFD_WP 0x00001000 /* wrprotect pages tracking */

int vm_insert_page(struct vm_area_struct *, uintptr_t addr, struct page *);

static inline unsigned long vma_pages(struct vm_area_struct *vma)
{
    return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
}

static inline void vm_flags_set(struct vm_area_struct *vma,
                                vm_flags_t flags)
{
    pr_todo();
}

#define pte_unmap_unlock(pte, ptl) \
    do                             \
    {                              \
        spin_unlock(ptl);          \
        pte_unmap(pte);            \
    } while (0)

/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)

/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */
#define PAGE_ALIGNED(addr)	IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)

static inline int __p4d_alloc(struct mm_struct *mm, pgd_t *pgd,
						unsigned long address)
{
	return 0;
}

static inline int __pud_alloc(struct mm_struct *mm, p4d_t *p4d,
						unsigned long address)
{
	return 0;
}

#ifndef pud_offset
static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
{
	return p4d;//todo
}
#define pud_offset pud_offset
#endif

int __pte_alloc_kernel(pmd_t *pmd);
int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address);

#define pfn_to_page(pfn) ((void *)((pfn) * PAGE_SIZE))//todo

#endif
